package com.cloud.local.lock.aop;

import com.cloud.local.lock.annotation.LocalLock;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @author zhaoyangfu - 2020/7/22 15:11
 */
@Aspect
@Configuration
public class LockMethodInterceptor {

    private static final Cache<String, Object> CACHE = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(5, TimeUnit.SECONDS)
            .build();

    @Around("@annotation(com.cloud.local.lock.annotation.LocalLock)")
    public Object interceptor(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        LocalLock lock = method.getAnnotation(LocalLock.class);
        String key = key(lock.key(), point.getArgs());
        if (!StringUtils.isEmpty(key)) {
            if (CACHE.getIfPresent(key) != null) {
                throw new RuntimeException("请勿重复请求");
            }
            CACHE.put(key, key);
        }
        try {
            return point.proceed();
        } finally {
            CACHE.invalidate(key);
        }
    }

    private String key(String keyExpress, Object[] args) {
        for (int i = 0; i < args.length; i++) {
            keyExpress = keyExpress.replace("arg[" + i + "]", args[i].toString());
        }
        return keyExpress;
    }
}
